package framework.view.components.container
{
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.geom.Transform;

import framework.view.components.scrollbar.IScrollable;
import framework.view.components.scrollbar.ScrollBar;
import framework.view.events.ScrollBarEvent;

public class ScrollableContainer extends Sprite implements IScrollable
{
	//==========================================================================
	//  Constructor
	//==========================================================================
	public function ScrollableContainer()
	{
		super();		
		initScroller();
	}
	//==========================================================================
	//  Variables
	//==========================================================================
	protected var scrollBar:ScrollBar;	
	protected var container:Sprite = new Sprite();
	//==========================================================================
	//  Properties
	//==========================================================================
	public function get bgSkin():DisplayObjectContainer
	{
		return scrollBar.bgSkin;
	}
	
	public function set bgSkin(value:DisplayObjectContainer):void
	{
		scrollBar.bgSkin = value;
	}
	
	public function get thumbSkin():DisplayObjectContainer
	{
		return scrollBar.thumbSkin;
	}
	
	public function set thumbSkin(value:DisplayObjectContainer):void
	{
		scrollBar.thumbSkin = value;
	}
    
    protected var _inner:Boolean = false;

    public function get inner():Boolean
    {
        return _inner;
    }

    public function set inner(value:Boolean):void
    {
        _inner = value;
        updateScrollBar();
    }
	
	protected var _scrollWidth:int = 0;
	
	public function set scrollWidth(value:int):void
	{
		_scrollWidth = value;
		updateScrollBar();
	}
	
	public function get scrollWidth():int
	{
		return _scrollWidth;
	}
	
	protected var _scrollHeight:int = 200;
	
	public function set scrollHeight(value:int):void
	{
		_scrollHeight = value;
		updateScrollBar();
	}
	
	public function get scrollHeight():int
	{
		return _scrollHeight;
	}
    
    protected var _scrollOffset:int = 2;
    
    public function set scrollOffset(value:int):void
    {
        _scrollOffset = value;
        updateScrollBar();
    }
    
    public function get scrollOffset():int
    {
        return _scrollOffset;
    }
    
    protected var _paddingTop:Number = 0;

    public function get paddingTop():Number
    {
        return _paddingTop;
    }

    public function set paddingTop(value:Number):void
    {
        _paddingTop = value;
    }

    protected var _paddingBottom:Number = 0;

    public function get paddingBottom():Number
    {
        return _paddingBottom;
    }

    public function set paddingBottom(value:Number):void
    {
        _paddingBottom = value;
    }

	protected var _scrollable:Boolean = true;
	
	public function set scrollable(value:Boolean):void
	{
		_scrollable = value;
		if (!_scrollable)
		{
			scrollBar.visible = false;
			scrollBar.removeEventListener(ScrollBarEvent.CHANGE, scrollChangeHandler); 
			container.scrollRect = null;
		}
		else
		{
			scrollBar.visible = true;
			scrollBar.addEventListener(ScrollBarEvent.CHANGE, scrollChangeHandler); 
			container.scrollRect = new Rectangle(0, 0, _scrollWidth, _scrollHeight);
		}
	}
	
	public function get scrollable():Boolean
	{
		return _scrollable;
	}
	
	public function get containerHeight():Number
	{
		//*/
		// Force DisplayObject update dimensions
		var bmpData:BitmapData = new BitmapData(1, 1);
		bmpData.draw(container);
		//*/
		
		return getFullBounds(container).height;
	}
	//==========================================================================
	//  Overridden methods: Sprite
	//==========================================================================
	override public function addChild(child:DisplayObject) : DisplayObject
	{
		child.addEventListener(Event.RESIZE, childRenderHandler);	
		container.addChild(child);
		updateScrollBar();
		return child;
	}
	
	override public function addChildAt(child:DisplayObject, index:int) : DisplayObject
	{
		child.addEventListener(Event.RESIZE, childRenderHandler);
		container.addChildAt(child, index);
		updateScrollBar();
		return child;
	}
	
	override public function removeChild(child:DisplayObject) : DisplayObject
	{
		if (container.contains(child))
		{
			child.removeEventListener(Event.RESIZE, childRenderHandler);
			return container.removeChild(child);
		}
		updateScrollBar();
		return child;
	}
	
	override public function removeChildAt(index:int) : DisplayObject
	{
		var child:DisplayObject = container.removeChildAt(index);
		child.removeEventListener(Event.RESIZE, childRenderHandler);
		updateScrollBar();
		return child;
	}
	
	override public function swapChildren(child1:DisplayObject, child2:DisplayObject) : void
	{
		container.swapChildren(child1, child2);
	}
	
	override public function swapChildrenAt(index1:int, index2:int) : void
	{
		container.swapChildrenAt(index1, index2);
	}
	
	override public function get numChildren() : int
	{
		return container.numChildren;
	}
	//==========================================================================
	//  Public methods
	//==========================================================================
	public function dispose():void
	{
		for (var i:int = 0; i < this.numChildren; i++)
		{
			var child:DisplayObject = this.getChildAt(i);
			child.removeEventListener(Event.RESIZE, childRenderHandler);
		}
		if (scrollBar)
		{
			if (scrollBar.parent)
			{
				scrollBar.parent.removeChild(scrollBar);
			}
			scrollBar.removeEventListener(ScrollBarEvent.CHANGE, scrollChangeHandler);    
			scrollBar.dispose();
			scrollBar = null;
		}
	}
	
	public function updateScrollBar():void
	{		
		container.scrollRect = new Rectangle(0, 0, _scrollWidth, _scrollHeight);
		if (inner)
		{
			scrollBar.x = container.x + _scrollWidth - scrollBar.width - scrollOffset;
		}
		else
		{
			scrollBar.x = container.x + _scrollWidth + scrollOffset;
		}
		scrollBar.y = paddingTop;
		scrollBar.barHeight = _scrollHeight - paddingTop - paddingBottom;
		if (_scrollHeight < containerHeight)
		{
			scrollBar.visible  = true;
		}
		else
		{
			scrollBar.visible  = false;
		}
	}
	//==========================================================================
	//  Protected methods
	//==========================================================================	
	protected function initScroller():void
	{
		super.addChild(container);
		
		scrollBar = new ScrollBar();
		scrollBar.y = container.y;
		super.addChild(scrollBar);
		scrollBar.addEventListener(ScrollBarEvent.CHANGE, scrollChangeHandler);    
	}
	
	protected function getFullBounds(displayObject:DisplayObject):Rectangle
	{
		var bounds:Rectangle;
		var transform:Transform;
		var toGlobalMatrix:Matrix; 
		var currentMatrix:Matrix;
		
		transform = displayObject.transform;
		currentMatrix = transform.matrix;
		toGlobalMatrix = transform.concatenatedMatrix;
		toGlobalMatrix.invert();
		transform.matrix = toGlobalMatrix;
		
		bounds = transform.pixelBounds.clone();
		
		transform.matrix = currentMatrix;
		
		return bounds;
	}
	//==========================================================================
	//  Event handlers
	//==========================================================================
	protected function childRenderHandler(event:Event):void
	{
		updateScrollBar();
	}
	
	//Scrollbar event handler
	protected function scrollChangeHandler(event:ScrollBarEvent):void
	{
		var rect:Rectangle = container.scrollRect;
		rect.y = (containerHeight + 5 - _scrollHeight) * scrollBar.value;
		if (rect.y < 0) rect.y = 0;
		container.scrollRect = rect;
	}
}
}

